#include "Ant.h"
#include "Food.h"
#include "Anthill.h"
#include "Pheromone.h"
#include "Area.h"
#include "Item.h"
#include <iostream>
#include <time.h>
#include <cstdlib> 
#include "AntColony.h"

class CItemCreator;
class CEnvironment;

CAnt::CAnt(void)
{
	SetPosition(NULL);
	m_uiStraightWay = 0;
	age = 0;
	food = 0;
	m_uiPheromonCount=0;
	m_uiPhAntReduction=0;
}


CAnt::~CAnt(void)
{
}

void CAnt::act(int id){

	if (age > g_uiMaxAntAge){
		Die();
		return;
	}
	if ( id != m_iActID)
	{
		//std::cout << "Ant acting" << std::endl;
		CalcMove();
		CheckForFood();
		if(0<food)
		{
			if(0==m_uiPheromonCount) // Food gefunden
			{
				m_uiPheromonCount=g_uiPheromonBaseAdd+g_uiPheromonCount/(lwaypoints.size()?lwaypoints.size():1);
				m_uiPhAntReduction=1;
			}
			CArea* pArea=GetPosition();
			//pArea->AddPheromone(g_uiPheromonBaseAdd+lwaypoints.size()*g_uiPheromonFactor);
			pArea->AddPheromone(m_uiPheromonCount);
			if(m_uiPheromonCount>=m_uiPhAntReduction)
			{
				m_uiPheromonCount-=m_uiPhAntReduction;
				if(m_uiPheromonCount==0)
				{
					m_uiPheromonCount=1;
				}
			}
			
		}
		else
		{
			m_uiPheromonCount=0;
		}
		age++;
	}
	m_iActID = id;

}
void CAnt::CleanWayBack(int const in_iDir)
{
	CArea * pCArea=nullptr;
	if (GetPosition() != nullptr)
	{
		switch(in_iDir)
		{
			case 0:
				pCArea=GetPosition()->GetNorthElement();
				break;
			case 1:
				pCArea=GetPosition()->GetEastElement();
				break;
			case 2:
				pCArea=GetPosition()->GetSouthElement();
				break;
			case 3:
				pCArea=GetPosition()->GetWestElement();
				break;
		}
	}
	if(nullptr!=pCArea)
	{
		CArea * pCAreaList=GetPosition();
		int iCount=1;
		for(std::list<int>::reverse_iterator rit=lwaypoints.rbegin();rit!=lwaypoints.rend() && nullptr!=pCAreaList;++rit)
		{
			switch(*rit)
			{
				case 2:
					pCAreaList=pCAreaList->GetNorthElement();
					break;
				case 3:
					pCAreaList=pCAreaList->GetEastElement();
					break;
				case 0:
					pCAreaList=pCAreaList->GetSouthElement();
					break;
				case 1:
					pCAreaList=pCAreaList->GetWestElement();
					break;
			}
			if(pCArea==pCAreaList)
			{
				for(int iIndex=0;iIndex<iCount;++iIndex)
				{
					lwaypoints.pop_back();
				}
				return;
			}
			++iCount;
		}
	}
	lwaypoints.push_back(in_iDir);
}
void CAnt::CalcMove(){
	int Dir = 0;
	int lastDir = 0;

	//Additional moves
	if( lwaypoints.size() > 0)
	{
		if(food == 0)
		{
			Dir=GetDir();
			CleanWayBack(Dir);
			m_uiStraightWay++;
		}
		else
		{
			lastDir=lwaypoints.back();
			//std::cout << "Bring back food "<< std::endl;
			lwaypoints.pop_back();
			if (lastDir == 0) Dir = 2;
			else if (lastDir == 1) Dir = 3;
			else if (lastDir == 2) Dir = 0;
			else if (lastDir == 3) Dir = 1;
		}
	}
	//First Move
	else
	{
		//std::cout << " First Move "<< std::endl;
		Dir = GetDir();
		lwaypoints.push_back(Dir);
		m_uiStraightWay++;
	}
	//std::cout << "Ant Moving from " << lastDir <<"to: " << Dir << std::endl;
	
	if (GetPosition() != NULL)
	{
		if (Dir==0 && GetPosition()->GetNorthElement() != NULL){
			//std::cout << "Ant Moving from to north" << std::endl;
			Move2(this->GetPosition()->GetNorthElement());
		
		}
		else if (Dir==1 && GetPosition()->GetEastElement() != NULL){
			Move2(this->GetPosition()->GetEastElement());
			//std::cout << "Ant Moving from to east" << std::endl;
		
		}
		else if (Dir==2 && GetPosition()->GetSouthElement() != NULL){
			Move2(this->GetPosition()->GetSouthElement());
			//std::cout << "Ant Moving from to south" << std::endl;
		
		}
		else if (Dir==3 && GetPosition()->GetWestElement() != NULL){
			Move2(this->GetPosition()->GetWestElement());
			//std::cout << "Ant Moving from to west" << std::endl;
		
		}
	}

	if (lwaypoints.size() >0 && food == 0 && CheckForAnthill()){
		lwaypoints.clear();
	}

	if (food > 0 && CheckForAnthill())
	{
		CAnthill* ptmpAnthill = dynamic_cast<CAnthill*>(GetPosition()->HasAnthill());
		ptmpAnthill->AddFood(food);
		lwaypoints.clear();
		food = 0;
		m_uiPheromonCount=0;
		m_uiPhAntReduction=0;
		age=0;
	}


	
}

void CAnt::Move2(CArea * TargetArea)
{
	
	GetPosition()->DeleteItem(this);
	SetPosition(TargetArea);
	GetPosition()->InsertItem(this);


}

int CAnt::CheckForFood(){

	CFood* ptmpFood;

	ptmpFood = dynamic_cast<CFood*>(GetPosition()->HasFood());

	if(ptmpFood != NULL){
		food+= ptmpFood->GetFood();
		//std::cout << "Found Food" << std::endl;
		return 1;
	
	}
	else
	{
		return 0;
	}


}

int CAnt::CheckForPheromone(){

	CPheromone* ptmpPheromone;

	ptmpPheromone = dynamic_cast<CPheromone*>(GetPosition()->HasType(4));

	if(ptmpPheromone != NULL){
		
		//std::cout << "Found Pheromone" << std::endl;
		return 1;
	
	}
	else{
		return 0;
	}


}

int CAnt::CheckForAnthill(){

	CAnthill* ptmpAnthill;

	ptmpAnthill = dynamic_cast<CAnthill*>(GetPosition()->HasAnthill());

	if(ptmpAnthill != NULL){
		
		//std::cout << "Found Anthill" << std::endl;
		return 1;
	
	}
	else 
	{
		return 0;
	}

}


// Random number function
int CAnt::GetDir()
{
	CArea* pCAreaN=this->GetPosition()->GetNorthElement();
	if(nullptr!=pCAreaN)
	{
		if(nullptr!=pCAreaN->HasFood())
		{
			return 0;
		}
	}
	CArea* pCAreaE=this->GetPosition()->GetEastElement();
	if(nullptr!=pCAreaE)
	{
		if(nullptr!=pCAreaE->HasFood())
		{
			return 1;
		}
	}
	CArea* pCAreaS=this->GetPosition()->GetSouthElement();
	if(nullptr!=pCAreaS)
	{
		if(nullptr!=pCAreaS->HasFood())
		{
			return 2;
		}
	}
	CArea* pCAreaW=this->GetPosition()->GetWestElement();
	if(nullptr!=pCAreaW)
	{
		if(nullptr!=pCAreaW->HasFood())
		{
			return 3;
		}
	}
	int iPhN=0;
	if(nullptr!=pCAreaN)
	{
		iPhN+=1+pCAreaN->CheckForPheromone();
	}
	int iPhE=0;
	if(nullptr!=pCAreaE)
	{
		iPhE+=1+pCAreaE->CheckForPheromone();
	}
	int iPhS=0;
	if(nullptr!=pCAreaS)
	{
		iPhS+=1+pCAreaS->CheckForPheromone();
	}
	int iPhW=0;
	if(nullptr!=pCAreaW)
	{
		iPhW+=1+pCAreaW->CheckForPheromone();
	}
	if (!lwaypoints.empty())
	{
		switch(lwaypoints.back())
		{
			case 2:
				iPhN=1;
				break;
			case 3:
				iPhE=1;
				break;
			case 0:
				iPhS=1;
				break;
			case 1:
				iPhW=1;
				break;
		}
	}
	const int iPhSum=iPhN+iPhE+iPhS+iPhW;
	if(iPhSum<5)
	{
		if(m_uiStraightWay < g_uiMinStraightWay && !lwaypoints.empty())
		{
			m_uiStraightWay++;
			return lwaypoints.back();
		}
	}
	m_uiStraightWay = 0;
	double dWN=static_cast<double>(RAND_MAX)*static_cast<double>(iPhN)/static_cast<double>(iPhSum);
	double dWE=static_cast<double>(RAND_MAX)*static_cast<double>(iPhE)/static_cast<double>(iPhSum);
	double dWS=static_cast<double>(RAND_MAX)*static_cast<double>(iPhS)/static_cast<double>(iPhSum);
	double dWW=static_cast<double>(RAND_MAX)*static_cast<double>(iPhW)/static_cast<double>(iPhSum);

	const double zahl = static_cast<double>(std::rand());

	if(zahl>dWN)
	{
		if(zahl>(dWN+dWE))
		{
			if(zahl>(dWN+dWE+dWS))
			{
				return 3;
			}
			else
			{
				return 2;
			}
		}
		else
		{
			return 1;
		}
	}
	else
	{
		return 0;
	}
}

void CAnt::Die(){
	GetPosition()->DeleteItem(this);
	delete this;
}